home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / cprog.EXE / C-DERSI5.C < prev    next >
C/C++ Source or Header  |  1996-06-25  |  11KB  |  293 lines

  1.  
  2.  
  3. Lesson 4.
  4.  
  5.                                                                          The
  6. operators of the language.
  7.  
  8.         I have mentioned that 'C' is a small language with most of the heavy
  9. work
  10. being done by explicit calls to library functions. There is however a rich
  11. mix of intrinsic operators which allow you to perform bit level operations,
  12. use pointers, and perform immediate operations on varables. In other words,
  13. most of a machine's instruction set is able to be used in the object program.
  14. At the time when 'C' was designed and first written these were unique for
  15. a high level language.
  16.  
  17.   Lets start with a discussion about precedence.
  18.  
  19.         This really means that the compiler puts invisable parentheses into
  20. your expression. Casting your mind back to Arithmetic in the primary school
  21. I expect you remember the nmemonic "My Dear Aunt Sally". The 'C' language
  22. does as well! So the following expression is correct
  23.  
  24.         15 + 4 * 11 = 59
  25.  
  26.         The compiler has rendered the expression as:
  27.  
  28.         15 + ( 4 * 11 ) = 59
  29.  
  30.         Now the 'C' language has a much larger collection of operators than
  31. just
  32. Multiply Divide Add Subtract, in fact much too big to try to remember the
  33. precedence of all of them. So my recomendation is to ALWAYS put in the
  34. parentheses, except for simple arithmetic. However, for the sake of
  35. completeness as much as anything else, here is the list.
  36.  
  37.         First up come what are called the primary-expression operators:
  38.  
  39.                 ()    Function.
  40.                 []    Array.
  41.                 .     struct member ( variable ).
  42.                 ->    struct member ( pointer ).
  43.  
  44.          The unary operators:
  45.  
  46.                 *     Indirection via a Pointer.
  47.                 &     Address of Variable.
  48.                 -     Arithmetic Negative.
  49.                 !     Logical Negation or Not.
  50.                 ~     Bit-wise One's Complement.
  51.                 ++    Increment.
  52.                 --    Decrement.
  53.                 sizeof  Which is self explanitary.
  54.  
  55.         Now the binary operators:
  56.  
  57.    Arithmetic Operators.
  58.  
  59.                 *     Multiply.                                       My
  60.                 /     Divide.                                         Dear
  61.                 %     Modulo, or Remainder of Integer Division.
  62.                 +     Addition.                                       Aunt
  63.                 -     Subtraction.                                    Sally
  64.  
  65.          The Shifting Operators.
  66.  
  67.                 >>    Bit-wise Shift to the Right.
  68.                 <<    Bit-wise Shift to the Left.
  69.  
  70.    Logical Relation Operators.
  71.  
  72.                 <     Less Than.
  73.                 >     Greater Than.
  74.                 <=    Less Than or Equal.
  75.                 >=    Greater Than or Equal.
  76.                 ==    Equal.
  77.                 !=    Not Equal.
  78.  
  79.          Bit-wise Boolean Operators.
  80.  
  81.                 &     Bit-wise And.
  82.                 ^     Bit-wise Exclusive-or.
  83.                 |     Bit-wise Or.
  84.  
  85.          The Logical Operators.
  86.  
  87.                 &&    Logical And.
  88.                 ||    Logical Or.
  89.  
  90.    The Assignment Operators. ( They all have the same priority. )
  91.  
  92.                 =     The normal assignment operator.
  93.  
  94.          The Self-referencing Assignment Operators.
  95.  
  96.                 +=
  97.                 -=
  98.                 *=
  99.                 /=
  100.                 %=
  101.                 >>=
  102.                 <<=
  103.                 &=
  104.     ^=
  105.                 |=
  106.  
  107.   Some explanation is in order here. The machine instructions in your
  108. computer include a suit of what are called "immediate operand" instructions.
  109. These instructions have one of the operands in a register and the other
  110. is either part of the instruction word itself ( if it is numerically small
  111. enough to fit ) or is the next word in the address space "immediately" after
  112. the instruction code word. 'C' makes efficient use of this machine feature
  113. by providing the above set of operations each of which translates directly
  114. to its corresponding machine instruction. When the variable in question is a
  115. 'register' one, or the optimiser is in use, the compiler output is just
  116. the one "immediate" machine instruction. Efficiency Personified!!!
  117.  
  118.         These two lines will make things clearer.
  119.  
  120.         a = 8;
  121.         a += 2;     /* The result is 10 */
  122.  
  123.         The exclusive-or operation is very useful you can toggle any
  124. combination
  125. of bits in the variable using it.
  126.  
  127.         a = 7;
  128.         a ^= 2;    /* Now a is 5 */
  129.         a ^= 2;    /*  and back to 7. */
  130.  
  131.         Naturally, you can use the other operations in exactly the same way,
  132. I'd like to suggest that you make a utterly simplistic little program
  133. and have a look at the assembler code output of the compiler. Don't be
  134. afraid of the assembler codes - they don't bite - and you will see
  135. what I was on about in the paragraph above.
  136.  
  137.         Historical Note and a couple of Cautions.
  138.  
  139.         In the Oldend Days when 'C' was first written all the self-referencing
  140. operations had the equals symbol and the operand around the other way.
  141. Until quite recently ( unix system V release 3.0 ) the 'C' compiler had a
  142. compatability mode and could cope with the old style syntax.
  143.  
  144.         A sample or test program is probably in order here.
  145.  
  146. /* ----------------------------------------- */
  147.  
  148. #include <stdio.h>
  149.  
  150. char *mes[] =
  151. {
  152.         "Your compiler",
  153.         " understands",
  154.         " does not understand",
  155.         " the old-fashioned self-referencing style."
  156.         };
  157.  
  158. main()
  159. {
  160.         int a;
  161.  
  162.         a = 5;
  163.         a=-2;
  164.         printf ( "%s %s %s\n", mes [ 0 ], mes [ ( a == -2 ) ? 2 : 1 ], mes [ 3
  165. ] );
  166.         }
  167.  
  168. /* ----------------------------------------- */
  169.  
  170.         The 'C' compiler issued with unix System V release 3.2 seems to have
  171. ( thankfully ) dropped the compatability mode. However a collegue, who
  172. was using an old compiler, and I spent hours trying to find this strange bug!
  173. The cure for the problem is either to put spaces on either side of the '=' sign
  174. or to bracket the unary minus to the operand.
  175.  
  176.         a=(-2);
  177.         a = -2;
  178.  
  179. Either is acceptable, and might save you a lot of spleen if sombody tries
  180. to install your work of art program on an ancient machine.
  181.  
  182.   The other caution is the use of the shifting instructions with signed
  183. and unsigned integers.
  184.  
  185.         If you shift a signed integer to the right when the sign bit is set
  186. then in all probability the sign will be extended. Once again a little
  187. demo program. Please cut it out of the news file with your editor
  188. and play with it.
  189.  
  190. /* ----------------------------------------- */
  191.  
  192. #ident "#(@) shifts.c - Signed / Unsigned integer shifting demo."
  193. #include <stdio.h>
  194.  
  195. #define WORD_SIZE ( sizeof ( INTEGER int ) * 8 )
  196. #define NIBBLE_SIZE 4
  197. #define NIBBLES_IN_WORD (( WORD_SIZE ) / NIBBLE_SIZE )
  198. #define SIGN_BIT ( 1 << ( WORD_SIZE - 1 ))
  199.  
  200. char *title[] =
  201. { "       Signed             Unsigned",
  202.         "                 Signed                                 Unsigned"
  203.         };
  204.  
  205. main ()
  206. {
  207.         INTEGER int a;
  208.         unsigned INTEGER int b, mask;
  209.         int ab, i, j, bit_counter, line_counter;
  210.  
  211.         a = b = SIGN_BIT;
  212.         printf ( "%s\n\n", title [ ( WORD_SIZE == 16 ) ? 0 : 1 ] );
  213.  
  214.         for ( line_counter = 0; line_counter < WORD_SIZE; line_counter++ )
  215.         {
  216.                 for ( ab = 0; ab < 2; ab++ )
  217.                 {
  218.                         mask = SIGN_BIT;
  219.                         for ( i = 0; i < NIBBLES_IN_WORD; i++ )
  220.                         {
  221.                                 for ( j = 0; j < NIBBLE_SIZE; j++ )
  222.                                 {
  223.                                         printf ( "%c", ((( ab ) ? b : a ) &
  224. mask ) ? '1' : '0' );
  225.                                         mask >>= 1;
  226.                                         }
  227.                                 printf ( " " );
  228.                                 }
  229.                         printf ( "%s", ( ab ) ? "\n" : " " );
  230.                         if ( ab )
  231.                         {
  232.                           b >>= 1;
  233.                                 }
  234.                         else
  235.                         {
  236.                                 a >>= 1;
  237. #if defined(FIX_COMPILER_BUG)
  238. # if (INTEGER == long)
  239.                                 a |= SIGN_BIT;    /* This is a work-around for
  240. the 3b2 compiler bug. */
  241. # endif
  242. #endif
  243.                                 }
  244.                         }
  245.                 }
  246.         }
  247.  
  248. /* ----------------------------------------- */
  249.  
  250.   This little program might well produce some interesting surprises on
  251. your machine in the same way it did on mine. I have an AT&T 3b2/400 and
  252. use the K & R style compiler. Interestingly, the above program did what
  253. I expected it to do when the integers were short, the sign bit is extended,
  254. but when the integers are long the sign bit is NOT extended. In this case
  255. the different behaviour is caused by the compiler always issuing a Logical
  256. Shift instruction, when it should issue a Arithmetic Shift instruction for
  257. signed integers and a Logical Shift instructon for unsigned ones. In the
  258. case of the short int the varable is loaded from memory into the register
  259. with a sign extend load instruction, this makes the Logical Shift instruction
  260. right work correctly for short ints, but not for longs.  I had to examine
  261. the assember codes output by the compiler in order to discover this.
  262.  
  263.   Here are the compiler invocation lines.
  264.  
  265. cc -olong.shifts -DFIX_COMPILER_BUG -DINTEGER=long shifts.c
  266.  
  267.         and
  268.  
  269. cc -oshort.shifts -DINTEGER=short shifts.c
  270.  
  271.         Experiment with the "-DFIX_COMPILER_BUG" and see what your compiler
  272. does.
  273.  
  274. Copyright notice:-
  275.  
  276. (c) 1993 Christopher Sawtell.
  277.  
  278. I assert the right to be known as the author, and owner of the
  279. intellectual property rights of all the files in this material,
  280. except for the quoted examples which have their individual
  281. copyright notices. Permission is granted for onward copying,
  282. but not modification, of this course and its use for personal
  283. study only, provided all the copyright notices are left in the
  284. text and are printed in full on any subsequent paper reproduction.
  285.  
  286. --
  287.  +----------------------------------------------------------------------+
  288.  | NAME   Christopher Sawtell                                           |
  289.  | SMAIL  215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.|
  290.  | EMAIL  chris@gerty.equinox.gen.nz                                    |
  291.  | PHONE  +64-3-389-3200   ( gmt +13 - your discretion is requested )   |
  292.  +----------------------------------------------------------------------+
  293.